/**
 * ---------------------------
 * Time: 2017/8/24 17:11.
 * Author: Cangshi
 * View: http://palerock.cn
 * ---------------------------
 */
(function () {
    var simplyHook = {
        /**
         * 劫持方法
         * @param context
         * @param methodName{string}
         * @param setting{{before:{function},current:{function},after:{function}}}
         */
        hook: function (context, methodName, setting) {
            if (context == null) {
                context = window;
            }
            if (typeof methodName != 'string') {
                throw new TypeError('劫持的参数必须为一个方法名');
            }
            var method = context[methodName];
            if (!method || !(method instanceof Function)) {
                throw new TypeError('方法名对应的欲劫持的方法不存在或他的类型不为Function');
            }
            if (!setting) {
                setting = {};
            }
            var hookedMethodStr = '(function () {\n';
            if (setting.before && setting.before instanceof Function) {
                hookedMethodStr = hookedMethodStr + 'setting.before.call(context, arguments);\n'
            }
            hookedMethodStr = hookedMethodStr + 'var result = null;\n';
            if (setting.current && setting.current instanceof Function) {
                hookedMethodStr = hookedMethodStr + 'result = setting.current.call(context, context, method, arguments);\n';
            } else {
                hookedMethodStr = hookedMethodStr + 'result = method.apply(context, arguments);\n';
            }
            if (setting.after && setting.after instanceof Function) {
                hookedMethodStr = hookedMethodStr + 'setting.after.call(context, arguments);\n';
            }
            hookedMethodStr = hookedMethodStr + 'return result;\n})';
            var hookedMethod = eval(hookedMethodStr);
            // var hookedMethod = function () {
            //     if (setting.before && setting.before instanceof Function) {
            //         setting.before.call(context, arguments);
            //     }
            //     var result = null;
            //     if (setting.current && setting.current instanceof Function) {
            //         result = setting.current.call(context, context, method, arguments);
            //     } else {
            //         result = method.apply(context, arguments);
            //     }
            //     if (setting.after && setting.after instanceof Function) {
            //         setting.after.call(context, arguments);
            //     }
            //     return result;
            // };
            // 注册hooking，便于取消hook
            var hookedMap = context.__sh_hooked_method_map;
            if (!hookedMap) {
                hookedMap = context.__sh_hooked_method_map = {}
            }
            if (!hookedMap.hasOwnProperty(methodName)) {
                hookedMap[methodName] = method;
            }
            // 替换目标方法
            context[methodName] = hookedMethod;
            return hookedMethod;
        },
        /**
         * 解除劫持
         * @param context 上下文
         * @param methodName 方法名
         * @return {boolean} 成功则为true，失败即为false
         */
        unhook: function (context, methodName) {
            var hookedMap = context.__sh_hooked_method_map;
            if (!hookedMap || !hookedMap.hasOwnProperty(methodName)) {
                console.warn('指定上下文中没有找到指定的方法[methodName = \'' + methodName + '\']被劫持');
                return false;
            }
            context[methodName] = hookedMap[methodName];
            return true;
        }
    };
    if (define) {
        define([], function () {
            return simplyHook;
        });
    } else {
        window.simplyHook = simplyHook;
    }
})();
